'use strict';
const { Model } = require('sequelize');
const moment = require('moment');
const { coursesIndex } = require('../utils/meilisearch');
moment.locale('zh-cn');
const { getKeysByPattern, delKey } = require('../utils/redis');

/**
 * 清除缓存
 * @param course
 * @returns {Promise<void>}
 */
async function clearCache(course = null) {
  let keys = await getKeysByPattern('courses:*');
  if (keys.length !== 0) {
    await delKey(keys);
  }

  if (course) {
    await delKey(`course:${course.id}`);
  }
}
module.exports = (sequelize, DataTypes) => {
  class Course extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */

    static associate(models) {
      //路由中condition使用了别名这里需要使用别名修改
      models.Course.belongsTo(models.Category, { as: 'category' });
      models.Course.belongsTo(models.User, { as: 'user' });
      models.Course.hasMany(models.Chapter, { as: 'chapter' });
      // 这里要用belongsToMany，来实现多对多关联，并且用through，也就是说要通过Likes中间表来实现关联。
      // 中间还加了个foreignKey，它是用来指明中间表里关联用的外键叫什么。
      // 通常来说，关联用的外键命名规范的话，是不需要明确指定foreignKey的。只有命名不规范的时候，才会用到foreignKey。但是在多对多关联里，不指定的话，会造成一个 Bug，会导致前面的添加点赞失败。
      // 可以将foreignKey删掉，重新提交一下，提示我们：课程 ID 字段定义了两次。这是Sequelize自身的问题，大家小心一点，将它定义出来就好。测完后，记得将它恢复。
      models.Course.belongsToMany(models.User, {
        through: models.Like,
        foreignKey: 'courseId',
        as: 'likeUsers',
      });
    }
  }

  Course.init(
    {
      categoryId: {
        type: DataTypes.INTEGER,
        allowNull: false,
        validate: {
          notNull: { msg: '分类ID必须填写。' },
          notEmpty: { msg: '分类ID不能为空。' },
          async isPresent(value) {
            const category = await sequelize.models.Category.findByPk(value);
            if (!category) {
              throw BadRequest(`ID为：${value} 的分类不存在。`);
            }
          },
        },
      },
      userId: {
        type: DataTypes.INTEGER,
        allowNull: false,
        validate: {
          notNull: { msg: '用户ID必须填写。' },
          notEmpty: { msg: '用户ID不能为空。' },
          async isPresent(value) {
            const user = await sequelize.models.User.findByPk(value);
            if (!user) {
              throw BadRequest(`ID为：${value} 的用户不存在。`);
            }
          },
        },
      },
      name: {
        type: DataTypes.STRING,
        allowNull: false,
        validate: {
          notNull: { msg: '名称必须填写。' },
          notEmpty: { msg: '名称不能为空。' },
          len: { args: [2, 45], msg: '名称长度必须是2 ~ 45之间。' },
        },
      },
      image: {
        type: DataTypes.STRING,
        validate: {
          isUrl: { msg: '图片地址不正确。' },
        },
      },
      recommended: {
        type: DataTypes.BOOLEAN,
        validate: {
          isIn: { args: [[true, false]], msg: '是否推荐的值必须是，推荐：true 不推荐：false。' },
        },
      },
      introductory: {
        type: DataTypes.BOOLEAN,
        validate: {
          isIn: {
            args: [[true, false]],
            msg: '是否入门课程的值必须是，推荐：true 不推荐：false。',
          },
        },
      },
      content: DataTypes.TEXT,
      likesCount: DataTypes.INTEGER,
      chaptersCount: DataTypes.INTEGER,
      createdAt: {
        type: DataTypes.DATE,
        get() {
          return moment(this.getDataValue('createdAt')).format('LL');
        },
      },
      updatedAt: {
        type: DataTypes.DATE,
        get() {
          return moment(this.getDataValue('updatedAt')).format('LL');
        },
      },
      free: {
        type: DataTypes.BOOLEAN,
        validate: {
          isIn: { args: [[true, false]], msg: '是否免费课程的值必须是，是：true 否：false。' },
        },
      },
    },

    {

      hooks: {
        // 在课程创建后
        afterCreate: async (course) => {
          await coursesIndex.addDocuments([
            {
              id: course.id,
              name: course.name,
              image: course.image || null,
              content: course.content || null,
              likesCount: course.likesCount || 0,
              updatedAt: course.updatedAt,
            },
          ]);
          if (process.env.NODE_ENV === 'production') { //本地没安装redis,生产才用
            await clearCache(course);
          }
        },
        // 在课程更新后
        afterUpdate: async (course) => {
          await coursesIndex.updateDocuments([
            {
              id: course.id,
              name: course.name,
              image: course.image,
              content: course.content,
              likesCount: course.likesCount,
              updatedAt: course.updatedAt,
            },
          ]);
          if (process.env.NODE_ENV === 'production') {
            await clearCache(course);
          }
        },
        // 在课程删除后
        afterDestroy: async (course) => {
          await coursesIndex.deleteDocument(course.id);
          if (process.env.NODE_ENV === 'production') {
            await clearCache(course);
          }
        },
      },
      sequelize,
      modelName: 'Course',
    }
  );
  return Course;
};
